use std::sync::LazyLock;

use super::Generator;
use glass::Reflect;
use log::error;
use rand::Rng;
use serde::{Deserialize, Serialize};
use serde_json::Value;

#[derive(Debug, Default, Reflect, Serialize, Deserialize)]
pub struct RegexTextGenerator {
    #[name("正则表达式")]
    pub regex: Option<String>,

    #[name("最大重复数")]
    pub max_repetition: Option<u32>,

    #[name("是否unicode")]
    pub unicode: Option<bool>,
}

static DEFAULT_REGEX: LazyLock<String> =
    LazyLock::new(|| String::from(r#"[\u4e00-\u9fa5]{0, 30}[_a-zA-Z]{0, 30}[0-9]{0, 30}"#));

impl Generator for RegexTextGenerator {
    fn generate(&self) -> Value {
        let unicode = self.unicode.unwrap_or(true);
        let regex = self.regex.as_ref().unwrap_or(&DEFAULT_REGEX);
        let max_repetition = self.max_repetition.unwrap_or(20);
        let mut parser = regex_syntax::ParserBuilder::new().unicode(unicode).build();
        let hir = parser.parse(regex.as_str());
        let hir = match hir {
            Ok(hir) => hir,
            Err(e) => {
                error!("regex generate failed: {e:?}");
                return Value::Null;
            }
        };

        let mut rng = rand::rng();
        let regex = rand_regex::Regex::with_hir(hir, max_repetition);
        let regex = match regex {
            Ok(regex) => regex,
            Err(e) => {
                error!("regex generate failed: {e:?}");
                return Value::Null;
            }
        };

        let result = rng.sample(&regex);
        Value::String(result)
    }
}

#[derive(Debug, Default, Reflect, Serialize, Deserialize)]
pub struct Ipv4Generator;

impl Generator for Ipv4Generator {
    fn generate(&self) -> Value {
        Value::from(format!(
            "{}.{}.{}.{}",
            rand::random::<u8>(),
            rand::random::<u8>(),
            rand::random::<u8>(),
            rand::random::<u8>()
        ))
    }
}

#[derive(Debug, Default, Reflect, Serialize, Deserialize)]
pub struct Ipv6Generator;

impl Generator for Ipv6Generator {
    fn generate(&self) -> Value {
        let ip_v6_field = || format!("{:02X}{:02X}", rand::random::<u8>(), rand::random::<u8>());
        Value::from(format!(
            "{}:{}:{}:{}:{}:{}:{}:{}",
            ip_v6_field(),
            ip_v6_field(),
            ip_v6_field(),
            ip_v6_field(),
            ip_v6_field(),
            ip_v6_field(),
            ip_v6_field(),
            ip_v6_field()
        ))
    }
}
